package middleware

import (
	"context"
	"errors"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/cloudwego/hertz/pkg/common/utils"
	"github.com/hertz-contrib/jwt"
	"gorm.io/gen"
    "gorm.io/gorm"
	"mall_frontend_api/biz/config"
	"mall_frontend_api/biz/consts"
	"mall_frontend_api/biz/dal"
	"mall_frontend_api/biz/pack"
	"mall_frontend_api/biz/util"
	"net/http"
	"time"
)

var (
	JwtMiddleware *jwt.HertzJWTMiddleware
	identityKey   = "identity"
)

func InitJwt() {
	var err error
	JwtMiddleware, err = jwt.New(&jwt.HertzJWTMiddleware{
		Realm:         "",
		Key:           []byte("frontend api secret key"),
		Timeout:       30*24 * time.Hour,
		MaxRefresh:    30*24 * time.Hour,
		TokenLookup:   "header:Authorization, query:token, cookie:jwt",
		TokenHeadName: "Bearer",
		LoginResponse: func(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) {
			c.Set(consts.JWTToken, token)
		},
		Authenticator: func(ctx context.Context, c *app.RequestContext) (interface{}, error) {
			var loginStruct struct {
				Account  string `form:"account" json:"account" query:"account" vd:"(len($) > 0 && len($) < 30); msg:'Illegal format'"`
				Password string `form:"password" json:"password" query:"password" vd:"(len($) > 0 && len($) < 30); msg:'Illegal format'"`
			}
			if err = c.BindAndValidate(&loginStruct); err != nil {
				return nil, err
			}
			userInfo, err := dal.NewInitDAO().UserDAO.GetByConditions(ctx, []gen.Condition{
				dal.User.Account.Eq(loginStruct.Account),
				dal.User.BizID.Eq(config.Values.BizID),
			})
			if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, err
			}
            if errors.Is(err, gorm.ErrRecordNotFound) {
			    return nil, errors.New("User does not exist or password is incorrect")
		    }

			if userInfo.Password != util.Md5(loginStruct.Password, true) {
				return nil, errors.New("User does not exist or password is incorrect")
			}

			return userInfo.ID, nil
		},
		IdentityKey: identityKey,
		Authorizator: func(data interface{}, ctx context.Context, c *app.RequestContext) bool {
			if v, ok := data.(float64); ok {
				userInfo, err := dal.NewInitDAO().UserDAO.GetInfoByID(ctx, int64(v))
				if err != nil {
					return false
				}
				c.Set(consts.JWTUserInfo, pack.RevertUserInfo(userInfo))
				return true
			}
			return false
		},
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			if v, ok := data.(int64); ok {
				return jwt.MapClaims{
					identityKey: v,
				}
			}
			return jwt.MapClaims{}
		},
		HTTPStatusMessageFunc: func(e error, ctx context.Context, c *app.RequestContext) string {
			hlog.CtxErrorf(ctx, "jwt biz err = %+v", e.Error())
			return e.Error()
		},
		Unauthorized: func(ctx context.Context, c *app.RequestContext, code int, message string) {
			c.JSON(http.StatusUnauthorized, utils.H{
				"message": message,
			})
		},
	})
}
